package pokeronlab_2014;

import java.util.prefs.InvalidPreferencesFormatException;

import pokeronlab_2014.mcts.MCTSDecision;

import com.biotools.meerkat.Action;
import com.biotools.meerkat.Card;
import com.biotools.meerkat.GameInfo;
import com.biotools.meerkat.Holdem;
import com.biotools.meerkat.Player;
import com.biotools.meerkat.util.Preferences;

/**
 * Controller osztály, a játéktól érkező függvényhívásokat implementálja.
 * 
 * @author andras
 * 
 */
public class Controller implements Player {
	/**
	 * Az aktuális játékra vonatkozó információ
	 */
	public static GameInfo thisGameInfo;
	/**
	 * Az MCTS döntéshozó példánya
	 */
	MCTSDecision mctsDecision;
	/**
	 * Az adatbázis példánya
	 */
	Database database;
	/**
	 * A szakértői rendszer példánya
	 */
	ExpertSystem expertSystem;
	/**
	 * Az opponent modeller példánya.
	 */
	OpponentModeller opponentModeller;
	/**
	 * A debug ablak
	 */
	public static DebugWindow debugWindow;	
	
	/**
	 * Getter az opponent modellerhez. 
	 * 
	 * @return Az opponent modeller példányát.
	 */
	public OpponentModeller getOpponentModeller(){
		return opponentModeller;
	}
	
	/**
	 * Konstruktor, a debug ablak létrehozása ebben történik
	 */
	public Controller() {	
		// a debugWindow fellövése
		if (debugWindow == null) {
			debugWindow = new DebugWindow();
		}
		debugWindow.setVisible(true);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see poker.Player#action()
	 */
	public Action getAction() {
		// defaulton callozunk
		int actionInt = Holdem.CALL;
		// preflop az expert system, flop után a döntéshozó
		// debug kapcsolók a config átírásával kapcsolhatóak át
		// //
		try {
			if (thisGameInfo.isPreFlop()
					//boolean-ná alakítjuk az "MCTSDecision" kulcshoz tartozó
					//stringet 
					&& Boolean.parseBoolean(ConfigManager.getInstance()
							.getValue("ExpertSystem"))) {
				debugWindow.printMessage("using expert system!");
				actionInt = expertSystem.getAction();
			} else if (!thisGameInfo.isPreFlop()
					&& Boolean.parseBoolean(ConfigManager.getInstance()
							.getValue("MCTSDecision"))) {
				actionInt = mctsDecision.getDecision();
				// elfogadható érték 0-2
			}
		} catch (InvalidPreferencesFormatException e) {
			// TODO Auto-generated catch block
			debugWindow.printMessage("Invalid config attribute!");
		}
		// Action lekérése az osztálytól a visszaadott int alapján
		// nem vagyok biztos benne, hogy mi a 3. param.
		int szorzo=2;
		if(thisGameInfo.isFlop() || thisGameInfo.isPreFlop())
			szorzo=1;
		
		Action actionObject = Action.getAction(actionInt,
				thisGameInfo.getAmountToCall(database.ourSeat), thisGameInfo.getBigBlindSize()*szorzo);
		// debug ablakba a cselekvés kiírása
		String tmp ="actionInt=" +actionInt;
		//debugWindow.printMessage(tmp);;
		debugWindow.printMessage(actionObject.toString());
		return actionObject;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see poker.Player#actionEvent(int, int, int)
	 */
	public void actionEvent(int pos, Action action) {
			
		database.addPlayerEvent(pos, action.getType(), thisGameInfo.getStage());
		//action 0-4 lehet valami
		
		
		String tmp2;
		int tmp4 =action.getType();
		switch (tmp4){
		case 0: tmp2 = "fold"; break;
		case 1: tmp2 = "check"; break;
		case 2: tmp2 = "call"; break;
		case 3: tmp2 = "bet"; break;
		case 4: tmp2 = "raise"; break;
		default: tmp2 = "egyéb cselekvés";
		}
		
		
		String tmp3 = "Opponent action= " + tmp2 + ", pos=" + pos;
		Controller.debugWindow.printMessage(tmp3);
		
		
		int Action = action.getType();
		if(Action==1 || Action ==2)
			Action=1;
		if(Action==3 || Action==4 || Action==8)
			Action=2;
		// szólunk a döntéshozónak, ha be van kapcsolva


		if((Action==0 || Action==1 || Action==2) && pos != database.ourSeat  )
			try {
				if(Boolean.parseBoolean(ConfigManager.getInstance().getValue(
						"MCTSDecision"))){
					//flopon beállítjuk a gyökerét egyébként
					if(!thisGameInfo.isPreFlop()){
						
						String tmp = "nextActivePlayer= " + mctsDecision.currentNode.rules.getPlayerID(pos) + ", pos= " + pos + ", Action= " + Action;
						Controller.debugWindow.printMessage(tmp);
					
						if(Action==2)
							mctsDecision.stepDownOneAction(Action, pos,  mctsDecision.currentNode.rules.fixlimit);
						else
							mctsDecision.stepDownOneAction(Action, pos,  0);
					}

				}
			} catch (InvalidPreferencesFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		
		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see poker.Player#gameOverEvent()
	 */
	public void gameOverEvent() {
		// TODO Auto-generated method stub
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see poker.Player#gameStartEvent(poker.GameInfo)
	 */
	public void gameStartEvent(GameInfo arg0) {
		thisGameInfo = arg0;
		String[] names = new String[10];
		for (int i = 0; i < 10; i++) {
			names[i] = thisGameInfo.getPlayerName(i);
		}
		database.newGame(names, thisGameInfo.getButtonSeat());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see poker.Player#init(poker.util.Preferences)
	 */
	public void init(Preferences arg0) {
		// A komponensek példányosítása illetve lekérése
		database = Database.getInstance();
		mctsDecision = new MCTSDecision();
		expertSystem = new ExpertSystem();
		opponentModeller = new OpponentModeller();

		// A komponensek ellenőrzése
		debugWindow.printMessage("Controller init done...");
	}

	/*
	 * A szék és a kártyák mentése a controllerbe
	 * 
	 * (non-Javadoc)
	 * 
	 * @see com.biotools.meerkat.Player#holeCards(com.biotools.meerkat.Card,
	 * com.biotools.meerkat.Card, int)
	 */
	public void holeCards(Card arg0, Card arg1, int arg2) {
		database.setOurSeat(arg2);
		database.addPlayerCards(arg2, arg0.getIndex(), arg1.getIndex());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see poker.Player#showdownEvent(int, poker.Card, poker.Card)
	 */
	public void showdownEvent(int arg0, Card arg1, Card arg2) {
		database.addPlayerCards(arg0, arg1.getIndex(), arg2.getIndex());
	}

	/*
	 * A stage event esetén a Controller átadja az adatbázisnak a boardot, és
	 * turnon meg riveren a döntéshozónak jelez, hogy leosztás történt.
	 * (non-Javadoc)
	 * 
	 * @see poker.Player#stageEvent(int)
	 */
	public void stageEvent(int arg0) {
		// preflop esetén nem updateljük a boardot, mert nincs
		
		Controller.debugWindow.printMessage("stage event");
		if (!thisGameInfo.isPreFlop()) {
			database.setBoard(thisGameInfo.getBoard().getCardArray());
		}
		// szólunk a döntéshozónak, ha be van kapcsolva
		try {
			if(Boolean.parseBoolean(ConfigManager.getInstance().getValue(
					"MCTSDecision"))){
				//flopon beállítjuk a gyökerét egyébként
				if(thisGameInfo.isFlop()){
					mctsDecision.setTreeRoot();
					mctsDecision.currentNode.rules.lastaction = thisGameInfo.getSmallBlindSeat();
				}
				else if (thisGameInfo.isTurn()) {
					mctsDecision.currentNode.rules.lastaction = thisGameInfo.getSmallBlindSeat();
					mctsDecision.stepDownOneNewCard(thisGameInfo.getBoard()
							.getCardIndex(3));
				} else if (thisGameInfo.isRiver()) {
					mctsDecision.currentNode.rules.lastaction = thisGameInfo.getSmallBlindSeat();
					mctsDecision.stepDownOneNewCard(thisGameInfo.getBoard()
							.getCardIndex(4));
				}
			}
		} catch (InvalidPreferencesFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.biotools.meerkat.GameObserver#winEvent(int, double,
	 * java.lang.String)
	 */
	public void winEvent(int arg0, double arg1, String arg2) {
		database.setWinner(thisGameInfo.getPlayerName(arg0));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.biotools.meerkat.GameObserver#dealHoleCardsEvent()
	 */
	public void dealHoleCardsEvent() {
		// TODO Auto-generated method stub

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.biotools.meerkat.GameObserver#gameStateChanged()
	 */
	public void gameStateChanged() {
		// TODO Auto-generated method stub

	}
	
	
	/* 
	 * Kidobjuk a debug ablakot
	 * (non-Javadoc)
	 * @see java.lang.Object#finalize()
	 */
	public void finalize(){
		debugWindow.dispose();
	}

}
